#ifndef FILEHELPER_H
#define FILEHELPER_H
#include "StompedReality/Core.h"
#include "StompedReality/Core/TypeSystem/TypeSystem.h"
#include <functional>
#include <string.h>
#include <vector>
#ifdef LINUX
#define FILE_SEPARATORE '/'
#define FILE_SEPARATORE_STR "/"
#endif
#ifdef WIN32
#define FILE_SEPARATORE '\\'
#define FILE_SEPARATORE_STR "\\"
#endif

typedef std::shared_ptr<Json::Value> JsonPTR;

namespace StompedReality
{
namespace Utility
{
struct FileInfo
{
  std::string name;
  std::string path;
  FileInfo( )
  {
    this->name = "";
    this->path = "";
  }

  FileInfo ( std::string n, std::string p )
  {
    this->name = n;
    this->path = p;
  }

};

//! \brief	List of FileInfos.
typedef std::vector<StompedReality::Utility::FileInfo> FileInfoList;

//! \brief	FileInfo list iterator.
typedef std::vector<StompedReality::Utility::FileInfo>::iterator FileInfoListIterator;

//! \brief	File Filter def.
typedef std::function<bool ( std::string ) > FileFilter;

/*!
 * \brief	File filter.
 *
 *    General file filter.
 *
 * \param	filter	Filter items. Example: ".png .jpg .gif"
 */
static std::function<StompedReality::Utility::FileFilter ( std::string& ) > GeneralFileFilter =
[&] ( std::string & filter )->StompedReality::Utility::FileFilter
{
  return [&] ( std::string n )->bool
         {
           int s = 0;
           int p = std::string::npos;
           while ( ( p = filter.find ( " ", s ) ) != std::string::npos )
           {
             if ( n.find ( filter.substr ( s, p - s ) ) != std::string::npos )
             {
               return true;
             }
             s = p + 1;
           }
           p = filter.size( );
           return n.find ( filter.substr ( s, p - s ) )  != std::string::npos;
         };
};

/*!
 * \brief	Json file filter.
 *
 *    Filters:
 *     - *.json
 */

/*static stomped_reality::utility::FileFilter JsonFileFilter = [&] ( std::string n )->bool
{
 return n.find ( ".json" ) != std::string::npos;
};*/

/*!
 * \brief	Image file filter.
 *
 *    Filters:
 *				- *.png
 *     - *.jpg
 *     - *.tga
 *     - *.gif
 */

static StompedReality::Utility::FileFilter ImageFileFilter = [&] ( std::string n )->bool
{
  return n.find ( ".png" ) != std::string::npos ||
         n.find ( ".jpg" ) != std::string::npos ||
         n.find ( ".tga" ) != std::string::npos ||
         n.find ( ".gif" ) != std::string::npos;
};

/*!
 * \author	Stefan Kazalski
 *
 * \brief	FileSystem.
 *
 *    Provides basic file operations.
 *    All operations are relative to the BasePath.
 */
class DLL_EXPORT FileSystem
{
 protected:

  std::string m_BasePath;

 public:

  //! \brief	Constructor.
  FileSystem( );

  //! \brief	Destructor.
  virtual ~FileSystem( );

  //! \brief	BasePath getter.
  void setBasePath ( std::string basePath );

  //! \brief	BasePath setter.
  std::string getBasePath( );

  //! \brief	Find files in BasePath.
  //! \param	filter		A FileFilter.
  //! \param	sub			A sub directory.
  //! \return	A list of FileInfos found as shared_ptr.
  std::shared_ptr<FileInfoList> findFiles ( FileFilter filter = [] ( std::string n )
                                            {
                                              return true;
                                            },
                                            std::string sub = "" );

  //! \brief Does file exists check.
  //! \param	fileName	The file.
  //! \return	True if file exists otherwise false.
  bool existsFile ( std::string fileName );

  //! \brief Does file exists check.
  //! \param	fileInfo	The files fileInfo.
  //! \return	True if file exists otherwise false.
  bool existsFile ( FileInfo fileInfo );

  //! \brief	Open json file
  //! \param	fileName	The file.
  //! \return	The json root as shared_ptr.
  JsonPTR openAsJson ( std::string fileName );

  //! \brief	Open json file
  //! \param	fileInfo	The files fileInfo.
  //! \return	The json root as shared_ptr.
  JsonPTR openAsJson ( FileInfo fileInfo );


  JsonPTR openAsJsonAbsolute ( std::string fileName );

  void saveJsonAbsolute ( Json::Value value, std::string fileName );

  void saveJson ( Json::Value value, std::string fileName );

  bool createDirectory ( std::string dir );

  template <class TYPE>
  void saveJson ( TYPE* obj, std::string fileName )
  {
	  auto typeInfo = StompedReality::type_system::TypeSystem::GetType<TYPE>();
	  Json::Value root;
	  typeInfo->write(root, (char*)obj);
	  this->saveJson(root,fileName);
  }

  template <class TYPE>
  void readJsonObject ( TYPE* obj, std::string fileName )
  {
	  auto typeInfo = StompedReality::type_system::TypeSystem::GetType<TYPE>();
	  auto jsonData = this->openAsJson(fileName);
	  typeInfo->read(*jsonData, (char*)obj);	  
  }
};

/*
class DLL_EXPORT FileHelper
{
 public:

  static bool isPath ( const char* dir );
  static bool findFilesInDir ( const char* dir, std::vector<std::string>* res );
  static bool findFilesInDir ( const char* dir, std::vector<std::string>* res, std::vector<std::string>* endings );
  static bool endsWith ( std::string x, std::string ending );
  static bool endsWith ( std::string x, std::vector<std::string>* endings );
  static bool createDirectory ( const char* dir );
  static std::string readFile ( const char* fileName );
  static bool existsFile ( const char* fileName );
};
*/
}
}
#endif // ifndef FILEHELPER_H
